package com.dlc.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.dto.AreaDto;
import com.dlc.shop.bean.dto.WarehouseDTO;
import com.dlc.shop.bean.enums.PurchasesStatusEnum;
import com.dlc.shop.bean.enums.TakeStockBillStatusEnum;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.vo.SkuStockVO;
import com.dlc.shop.bean.vo.StockPointSkuVO;
import com.dlc.shop.bean.vo.StockPointVO;
import com.dlc.shop.bean.vo.WarehouseVO;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.*;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ResponseEnum;
import com.dlc.shop.common.util.BeanUtil;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.common.util.PrincipalUtil;
import com.dlc.shop.common.util.RedisUtil;
import com.dlc.shop.dao.*;
import com.dlc.shop.manager.impl.StockManager;
import com.dlc.shop.service.*;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author FrozenWatermelon
 * @date 2023-11-08 11:11:44
 */
@Service
@AllArgsConstructor
public class WarehouseServiceImpl extends ServiceImpl<WarehouseMapper, Warehouse> implements WarehouseService {


    private final WarehouseMapper warehouseMapper;
    private final WarehouseAreaService warehouseAreaService;
    private final AllotOrderMapper allotOrderMapper;
    private final PurchaseOrderMapper purchaseOrderMapper;
    private final TakeStockMapper takeStockMapper;
    private final SegmentService segmentService;
    private final StockManager stockManager;
    private final ShopDetailMapper shopDetailMapper;
    private final AreaService areaService;
    private final StockPointSkuService stockPointSkuService;

    @Override
    public IPage<WarehouseVO> page(PageParam<WarehouseVO> pageParam, WarehouseDTO warehouseDTO) {
        List<WarehouseVO> pageVO = warehouseMapper.list(pageParam, warehouseDTO);
        if (pageVO.isEmpty()) {
            return pageParam;
        }
        if (Objects.nonNull(warehouseDTO.getSkuId())) {
            List<Long> warehouseIds = pageVO.stream().map(WarehouseVO::getWarehouseId).collect(Collectors.toList());
            List<StockPointSkuVO> stockPointSkuList = new ArrayList<>(warehouseIds.size());
            for (Long stockPointId : warehouseIds) {
                StockPointSkuVO stockPointSkuVO = new StockPointSkuVO();
                stockPointSkuVO.setStockPointId(stockPointId);
                stockPointSkuVO.setSkuId(warehouseDTO.getSkuId());
                stockPointSkuList.add(stockPointSkuVO);
            }
            List<SkuStockVO> skuStockVOList = stockManager.convertSkuStock(stockPointSkuList);
            Map<Long, Integer> stockMap = skuStockVOList.stream().collect(Collectors.toMap(SkuStockVO::getStockPointId, SkuStockVO::getStock));
            for (WarehouseVO warehouseVO : pageVO) {
                warehouseVO.setStock(stockMap.containsKey(warehouseVO.getWarehouseId()) ? stockMap.get(warehouseVO.getWarehouseId()) : 0);
            }
        }
        for (WarehouseVO warehouseVO : pageVO) {
            if (StrUtil.isNotBlank(warehouseVO.getPhone()) && PrincipalUtil.isMobile(warehouseVO.getPhone())) {
                warehouseVO.setPhone(PhoneUtil.hideBetween(warehouseVO.getPhone()).toString());
            }
        }
        pageParam.setRecords(pageVO);
        pageParam.setTotal(warehouseMapper.list(null, warehouseDTO).size());
        return pageParam;
    }

    @Override
    @Cacheable(cacheNames = ProductCacheNames.WAREHOUSE_BY_ID_PREFIX, key = "#warehouseId", sync = true)
    public WarehouseVO getByWarehouseId(Long warehouseId) {
        WarehouseVO warehouse = warehouseMapper.getByWarehouseId(warehouseId);
        if (warehouse == null) {
            return null;
        }
        List<Long> areaIds = warehouseMapper.getWarehouseAreaByWarehouseId(warehouseId);
        warehouse.setCityList(areaService.listByAreaIdList(areaIds));
        return warehouse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WarehouseDTO insertWarehouseAndArea(WarehouseDTO warehouseDTO) {
        this.checkIsRepeat(warehouseDTO);
        Warehouse warehouse = BeanUtil.map(warehouseDTO, Warehouse.class);
        if (Objects.isNull(warehouseDTO.getWarehouseId())) {
            Long dateFormatSegmentId = segmentService.getDateFormatSegmentId(SegmentIdKey.STOCK_POINT);
            warehouse.setWarehouseId(dateFormatSegmentId);
            warehouseDTO.setWarehouseId(dateFormatSegmentId);
        }
        warehouse.setCreateTime(new Date());
        warehouse.setUpdateTime(new Date());
        // 插入仓库
        warehouseMapper.save(warehouse);
        // 插入供应城市数据
        insertWarehouseArea(warehouse.getWarehouseId(), warehouseDTO.getCityList());
        return warehouseDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = ProductCacheNames.WAREHOUSE_BY_ID_PREFIX, key = "#warehouseDTO.warehouseId")
    public void updateWarehouseAndArea(WarehouseDTO warehouseDTO) {
        WarehouseVO warehouseDb = warehouseMapper.getByWarehouseId(warehouseDTO.getWarehouseId());
        this.checkIsRepeat(warehouseDTO);
        if (!Objects.equals(warehouseDb.getShopId(), warehouseDTO.getShopId())) {
            throw new YamiShopBindException(ResponseEnum.UNAUTHORIZED);
        }
        if (!PrincipalUtil.isDbPhone(warehouseDTO.getPhone(), warehouseDb.getPhone(), true)) {
            throw new YamiShopBindException("请输入正确的手机号");
        }
        if (warehouseDTO.getPhone().contains(Constant.ASTERISK)) {
            warehouseDTO.setPhone(warehouseDb.getPhone());
        }
        // 更新运费模板
        warehouseMapper.update(BeanUtil.map(warehouseDTO, Warehouse.class));
        // 删除供应城市
        warehouseAreaService.deleteByWarehouseId(warehouseDTO.getWarehouseId());
        // 添加供应城市关系
        insertWarehouseArea(warehouseDTO.getWarehouseId(), warehouseDTO.getCityList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WarehouseVO deleteWarehouseAndArea(Long warehouseId) {
        WarehouseVO warehouseVO = warehouseMapper.getByWarehouseId(warehouseId);
        if (warehouseVO.getType() == 0) {
            throw new YamiShopBindException("yami.default.warehouse.not.delete");
        }
        // 检查库存
        List<StockPointSkuVO> pointSkuList = stockPointSkuService.listByPointId(warehouseId);
        if (pointSkuList.size() > 0) {
            throw new YamiShopBindException("yami.stock.point.exit");
        }
        // 检查采购订单
        Long unFinishCount = purchaseOrderMapper.selectCount(new LambdaQueryWrapper<PurchaseOrder>()
                .eq(PurchaseOrder::getWarehouseId, warehouseId)
                .notIn(PurchaseOrder::getStatus, PurchasesStatusEnum.COMPLETION.value(), PurchasesStatusEnum.VOIDED.value()));
        if (unFinishCount > 0) {
            throw new YamiShopBindException("yami.unfinish.purchase.order.exist");
        }
        // 检查调拨订单
        unFinishCount = allotOrderMapper.selectCount(new LambdaQueryWrapper<AllotOrder>()
                .and(w -> w.eq(AllotOrder::getOutWarehouseId, warehouseId)
                        .or().eq(AllotOrder::getInWarehouseId, warehouseId))
                .notIn(AllotOrder::getStatus, AllotOrderStatusEnum.COMPLETION.getNum(), AllotOrderStatusEnum.VOIDED.getNum()));
        if (unFinishCount > 0) {
            throw new YamiShopBindException("yami.unfinish.allot.order.exist");
        }
        // 检查实物盘点
        unFinishCount = takeStockMapper.selectCount(new LambdaQueryWrapper<TakeStock>()
                .eq(TakeStock::getWarehouseId, warehouseId)
                .eq(TakeStock::getBillStatus, TakeStockBillStatusEnum.TAKING.value()));
        if (unFinishCount > 0) {
            throw new YamiShopBindException("yami.unfinish.takestock.exist");
        }
        warehouseAreaService.deleteByWarehouseId(warehouseId);
        // 删除运费模板
        warehouseMapper.deleteById(warehouseId);
        return warehouseVO;
    }

    @Override
    public void removeWarehouseCache(Long warehouseId, Long shopId, Integer sysType) {
        List<String> keys = new ArrayList<>(Constant.INITIAL_CAPACITY);
        if (Objects.nonNull(warehouseId)) {
            keys.add(CacheNames.WAREHOUSE_BY_ID_PREFIX + CacheNames.UNION + warehouseId);
        }
        keys.add(CacheNames.WAREHOUSE_BY_ID_PREFIX + CacheNames.UNION + warehouseId);
        keys.add(DeliveryCacheNames.SHOP_WAREHOUSE_LIST_PREFIX + CacheNames.UNION + shopId + CacheNames.UNION_KEY + sysType);
        RedisUtil.deleteBatch(keys);
    }

    @Override
    public void createWarehouseByShopId(Long shopId, Integer sysType, String phone, String name) {
        Warehouse warehouse = new Warehouse();
        warehouse.setWarehouseId(segmentService.getDateFormatSegmentId(SegmentIdKey.STOCK_POINT));
        warehouse.setShopId(shopId);
        warehouse.setSysType(sysType);
        warehouse.setType(0);
        warehouse.setWarehouseName("默认仓库");
        warehouse.setPhone(phone);
        warehouse.setManage(name);
        warehouse.setCreateTime(new Date());
        warehouse.setUpdateTime(new Date());
        warehouseMapper.save(warehouse);
    }

    @Override
    public List<Long> listWarehouseAreaByShopId(Long shopId, Integer sysType, Long warehouseId) {
        return warehouseMapper.listareaByShopIdAndSysType(shopId, sysType, warehouseId);
    }

    @Override
    public List<WarehouseVO> listWarehouse(WarehouseDTO warehouseDTO) {;
        return warehouseMapper.list(null, warehouseDTO);
    }

    @Override
    public List<WarehouseVO> listCanDeliveryWarehouse(WarehouseDTO warehouseDTO) {
        // 按areaId获取可配送的仓库（区域仓库和默认仓库都查出来）
        List<WarehouseVO> warehouses = warehouseMapper.listCanDeliveryWarehouse(warehouseDTO);
        // 区分区域仓库和默认仓库
        Set<Long> shopIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        List<WarehouseVO> areaWarehouses = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<WarehouseVO> defaultWarehouses = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (WarehouseVO warehouse : warehouses) {
            if (Objects.equals(warehouse.getType(), 0)) {
                defaultWarehouses.add(warehouse);
            } else {
                areaWarehouses.add(warehouse);
                shopIds.add(warehouse.getShopId());
            }
        }
        // 若店铺的可配送的区域仓库不存在则使用默认仓库
        for (WarehouseVO defaultWarehouse : defaultWarehouses) {
            if (shopIds.add(defaultWarehouse.getShopId())) {
                areaWarehouses.add(defaultWarehouse);
            }
        }
        return areaWarehouses;
    }

    @Override
    public WarehouseVO getDefaultWarehouseByShopId(Long shopId, Integer sysType) {
        return warehouseMapper.getDefaultWarehouseIdByShopId(shopId,sysType);
    }

    @Override
    @Cacheable(cacheNames = DeliveryCacheNames.SHOP_WAREHOUSE_LIST_PREFIX, key = "#shopId + ':' + #sysType")
    public List<WarehouseVO> listWarehouseByShopId(Long shopId, Integer sysType) {
        List<WarehouseVO> warehouseVOS = warehouseMapper.listWarehouseByShopId(shopId, sysType);
        // 将默认仓库放到第一位
        warehouseVOS.sort(Comparator.comparing(WarehouseVO::getType));
        return warehouseVOS;
    }

    @Override
    public void intiWarehouse() {
        List<Warehouse> warehouseList = new ArrayList<>();
        WarehouseDTO warehouseDTO = new WarehouseDTO();
        warehouseDTO.setSysType(SysTypeEnum.MULTISHOP.value());
        warehouseDTO.setType(0);
        List<Warehouse> list = warehouseMapper.selectList(new LambdaQueryWrapper<Warehouse>()
                .eq(Warehouse::getType, 0)
                .eq(Warehouse::getSysType, SysTypeEnum.MULTISHOP.value())
        );
        List<Long> shopIds = list.stream().map(Warehouse::getShopId).toList();
        // 初始化店铺默认仓库
        List<ShopDetail> shopList = shopDetailMapper.selectList(new LambdaQueryWrapper<>(ShopDetail.class));

        if (CollectionUtil.isNotEmpty(shopList)) {
            shopList.forEach(shop-> {
                if (shopIds.contains(shop.getShopId())) {
                    return;
                }
                Warehouse warehouse = new Warehouse();
                warehouse.setShopId(shop.getShopId());
                warehouse.setManage(shop.getUserName());
                warehouse.setPhone(shop.getTel());
                warehouse.setSysType(SysTypeEnum.MULTISHOP.value());
                warehouseList.add(warehouse);
            });
        }
        if (!warehouseList.isEmpty()) {
            warehouseList.forEach( s-> {
                s.setWarehouseId(segmentService.getDateFormatSegmentId(SegmentIdKey.STOCK_POINT));
                s.setWarehouseName("默认仓库");
                s.setType(0);
            });
            warehouseMapper.batchSave(warehouseList);
        }
    }

    @Override
    public List<WarehouseVO> listDefaultWarehouses() {
        return warehouseMapper.listDefaultWarehouses();
    }

    @Override
    public StockPointVO getWarehousePoint(Long shopId, Integer sysType) {
        StockPointVO stockPointVO = new StockPointVO();
        List<WarehouseVO> warehouseVOS = warehouseMapper.listWarehouseByShopId(shopId, sysType);
        stockPointVO.setWarehouseSize(warehouseVOS.size());
        for (WarehouseVO warehouseVO : warehouseVOS) {
            if (warehouseVO.getType() == 0) {
                stockPointVO.setDefaultWarehouseId(warehouseVO.getWarehouseId());
                break;
            }
        }
        return stockPointVO;
    }

    @Override
    public List<WarehouseVO> listWarehouseAndStationByShopIds(List<Long> shopIds) {
        if (CollUtil.isEmpty(shopIds)) {
            return Collections.emptyList();
        }
        return warehouseMapper.listWarehouseAndStationByShopIds(shopIds);
    }

    private void checkIsRepeat(WarehouseDTO warehouseDTO) {
        int count = warehouseMapper.countByWarehouseName(warehouseDTO.getShopId(), warehouseDTO.getWarehouseName(), warehouseDTO.getSysType(), warehouseDTO.getWarehouseId());
        if (count > 0) {
            throw new YamiShopBindException("仓库名称已存在，请重新输入");
        }
        // 查询是否已经存在重复供应城市，一个城市只能有一个区域仓库
        if (warehouseDTO.getType() == 1) {
            if (CollectionUtil.isEmpty(warehouseDTO.getCityList())) {
                throw new YamiShopBindException("区域仓库必须要有供应城市");
            }
            List<Long> cityList = warehouseMapper.listareaByShopIdAndSysType(warehouseDTO.getShopId(), warehouseDTO.getSysType(), warehouseDTO.getWarehouseId());
            if (CollectionUtil.isNotEmpty(cityList)) {
                for (AreaDto areaDTO : warehouseDTO.getCityList()) {
                    if (cityList.contains(areaDTO.getAreaId())) {
                        throw new YamiShopBindException(areaDTO.getAreaName() + " 已有区域仓库，请重新选择");
                    }
                }
            }
        }
    }

    private void insertWarehouseArea(Long warehouseId, List<AreaDto> areaDTOList) {
        List<WarehouseArea> warehouseAreaList = new ArrayList<>(areaDTOList.size());
        for (AreaDto areaDTO : areaDTOList) {
            WarehouseArea warehouseArea = new WarehouseArea();
            warehouseArea.setWarehouseId(warehouseId);
            warehouseArea.setAreaId(areaDTO.getAreaId());
            warehouseAreaList.add(warehouseArea);
        }
        warehouseAreaService.saveBatch(warehouseAreaList);
    }
}
